# coding:utf-8
import struct
from PySide6 import QtCore
from PySide6.QtCore import Slot, QTimer, Signal
from PySide6.QtWidgets import QWidget
import serial.tools.list_ports_linux    #windows下
from APP.H510Test.Handle.serialH510Testhandle import SerialH510TestHandle
from Util.util import HexToStrOnTime, BytesToStrOnTime
from APP.H510Test.SendData.SendH510Data import Send510ContralCode
from APP.H510Test.UI.H510TestForm import Ui_mainForm
import re

from qfluentwidgets import TeachingTip, TeachingTipTailPosition, InfoBarIcon


class FocusInterface_H510Test(QWidget, Ui_mainForm):
    ThemeSignal = Signal(int)  # 0: 跟随系统; 1: 明亮; 2: 暗黑

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setupUi(self)
        plist = list(serial.tools.list_ports.comports())   #windows下
        # plist = glob.glob('/dev/tty[A-Za-z]*')              #Linux下
        self.m_SerialsComboList = []
        if len(plist) <= 0:
            # print(u'没有发现端口！')
            pass
        else:
            for plist1 in plist:  # Windows
                plist2 = list(plist1)  # Windows
                self.m_SerialsComboList.append(plist2[1])  # Windows
            # self.m_SerialsComboList = plist[0]            #Linux
        # print(self.m_SerialsComboList)
        self.SerialCombo_box.addItems(self.m_SerialsComboList)
        self.BaudRateCombo_box.addItems(['300', '600', '1200', '2400', '4800',
                                         '9600', '14400', '19200', '38400', '56000',
                                         '57600', '115200', '128000', '256000', '460800',
                                         '512000'])
        # self.ThemeCombo_box.addItems([u'明亮', u'暗黑', u'跟随系统'])
        # self.ThemeCombo_box.setCurrentIndex(1)
        self.BaudRateCombo_box.setCurrentIndex(7)
        self.serialHandle = SerialH510TestHandle()
        self.serialHandle.EventH510TestSignal.connect(self.EventSlot)  # type: ignore
        self.SerialCombo_box.currentTextChanged['QString'].connect(
            self.OnSelectCom)  # type: ignore
        self.BaudRateCombo_box.currentTextChanged['QString'].connect(
            self.OnSelectBaudRate)  # type: ignore
        self.OpenSerial_pribtn.clicked.connect(self.OnOpenComPressed)  # type: ignore

        self.ClearTx_pribtn.clicked.connect(self.OnClearTxData)     # type: ignore
        self.ClearRx_pribtn.clicked.connect(self.OnClearRxData)     # type: ignore

        self.serialHandle.H510TestReceiveDataSignal.connect(self.DataReceiveSlot)  # type: ignore
        self.LeftSpeed_slider.setRange(-255, 255)
        self.LeftSpeed_slider.setSingleStep(1)
        self.LeftSpeed_slider.setValue(0)
        self.LeftSpeed = 0
        self.LeftSpeed_slider.valueChanged.connect(self.OnLeftSliderChange)
        self.LeftSpeed_edit.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhDigitsOnly)
        self.LeftSpeed_edit.setText(str(0.0))
        self.LeftSpeed_edit.editingFinished.connect(self.OnLeftEditTextChanged)

        self.RightSpeed_slider.setRange(-255, 255)
        self.LeftSpeed_slider.setSingleStep(1)
        self.RightSpeed_slider.setValue(0)
        self.RightSpeed = 0
        self.RightSpeed_slider.valueChanged.connect(self.OnRightSliderChang)
        self.RightSpeed_edit.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhDigitsOnly)
        self.RightSpeed_edit.setText(str(0.0))
        self.RightSpeed_edit.editingFinished.connect(self.OnRightEditTextChanged)

        self.SingleSend_btn.clicked.connect(self.SendData)  # type: ignore
        self.IsAotoSend_sbtn.checkedChanged.connect(self.AutoSend)  # type: ignore
        self.ArmUp_sbtn.pressed.connect(self.OnArmUpbtnIsPressed)  # type: ignore
        self.ArmDown_sbtn.pressed.connect(self.OnArmDownbtnIsPressed)   # type: ignore
        self.ArmUp_sbtn.released.connect(self.OnArmbtnNonePressed)  # type: ignore
        self.ArmDown_sbtn.released.connect(self.OnArmbtnNonePressed)    # type: ignore

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.SendData)
        self.ArmState = 0

    @Slot(bool)
    def EventSlot(self, message):
        if message:
            self.OpenSerial_pribtn.setText(u'关闭串口')
        else:
            self.OpenSerial_pribtn.setText(u'打开串口')
        pass

    @Slot(list)
    def DataReceiveSlot(self, message):
        self.DateRece_textedit.appendPlainText(HexToStrOnTime(message).upper())
        LSpeed = struct.unpack('b', struct.pack('B', message[2]))[0] * 0.02
        RSpeed = struct.unpack('b', struct.pack('B', message[3]))[0] * 0.02
        # print(str(LSpeed) + " : " + str(RSpeed))
        self.LeftSpeedLabel.setText(u'左轮速：' + str(round(LSpeed, 2)) + ' m/s')
        self.RightSpeedLabel.setText(u'右轮速：' + str(round(RSpeed, 2)) + ' m/s')
        stateIndex = message[1] & 0x03
        if stateIndex == 0x00:
            self.Battery1_label.setText(u'电池1: ' + str(round(message[7] * 0.2, 2)) + 'V')
        elif stateIndex == 0x01:
            self.Battery2_label.setText(u'电池2: ' + str(round(message[7] * 0.2, 2)) + 'V')
            self.ArmAngle_label.setText(u'鳍臂角度: ' + str(message[6] * 2) + '°')
        elif stateIndex == 0x02:
            self.Battery3_label.setText(u'电池3: ' + str(round(message[7] * 0.2, 2)) + 'V')
        else:
            self.Battery4_label.setText(u'电池4: ' + str(round(message[7] * 0.2, 2)) + 'V')
            self.SystemV_label.setText(u'系统电压: ' + str(round(message[6] * 0.2, 2)) + 'V')





        pass

    @Slot(str)
    def OnSelectCom(self, message):
        # print("选择了" + message)
        pass

    @Slot()
    def OnLeftSliderChange(self):
        self.LeftSpeed = int(self.LeftSpeed_slider.value())
        # valk = struct.unpack('b', val.to_bytes(1, 'big', signed=False))
        # print(str(valk[0]))
        self.LeftSpeed_edit.setText(str(round(self.LeftSpeed * 0.01, 2)))
        # print(u'LeftSpeed: ' + str(self.LeftSpeed))

    @Slot()
    def OnRightSliderChang(self):
        self.RightSpeed = int(self.RightSpeed_slider.value())
        self.RightSpeed_edit.setText(str(round(self.RightSpeed * 0.01, 2)))
        # print(u'RightSpeed: ' + str(self.RightSpeed))

    @Slot()
    def OnOpenComPressed(self):
        # print(u'pressed')

        if not self.serialHandle.openSerialPort(self.SerialCombo_box.currentText()):
            self.showBottomTip(self.OpenSerial_pribtn, u'当前端口已被占用，或存在问题，无法打开！')
        pass

    @Slot()
    def OnClearTxData(self):
        self.DateSend_textedit.clear()
        pass

    @Slot()
    def OnClearRxData(self):
        self.DateRece_textedit.clear()
        pass

    @Slot()
    def OnLeftEditTextChanged(self):
        text = self.LeftSpeed_edit.text()
        if self.is_signed_decimal(text):
            value = float(text)
            if value >= -2.55 and value <= 2.55:
                self.LeftSpeed = int(value / 0.01)
                self.LeftSpeed_slider.setValue(self.LeftSpeed)
                # print(u'LeftSpeed: ' + str(self.LeftSpeed))
            else:
                self.showBottomTip(self.LeftSpeed_edit, u'请输入数字! 输入范围(-2.55 ~ 2.55)')
                self.LeftSpeed_edit.setText(str(round(self.LeftSpeed * 0.01, 2)))

        else:
            self.showBottomTip(self.LeftSpeed_edit, u'请输入数字! 输入范围(-2.55 ~ 2.55)')
            self.LeftSpeed_edit.setText(str(round(self.LeftSpeed * 0.01, 2)))
        pass

    @Slot()
    def OnRightEditTextChanged(self):
        text = self.RightSpeed_edit.text()
        if self.is_signed_decimal(text):
            value = float(text)
            if value >= -2.55 and value <= 2.55:
                self.RightSpeed = int(value / 0.01)
                self.RightSpeed_slider.setValue(self.RightSpeed)
                # print(u'RightSpeed: ' + str(self.RightSpeed))
            else:
                self.showBottomTip(self.RightSpeed_edit, u'请输入数字! 输入范围(-2.55 ~ 2.55)')
                self.RightSpeed_edit.setText(str(round(self.RightSpeed * 0.01, 2)))
        else:
            self.showBottomTip(self.RightSpeed_edit, u'请输入数字! 输入范围(-2.55 ~ 2.55)')
            self.RightSpeed_edit.setText(str(round(self.RightSpeed * 0.01, 2)))

    def closeEvent(self, a0):
        self.timer.stop()
        self.serialHandle.closeSerialPort()
        pass

    def showBottomTip(self, Target, message):
        TeachingTip.create(
            target=Target,
            icon=InfoBarIcon.ERROR,
            title='提示：',
            content=message,
            isClosable=True,
            tailPosition=TeachingTipTailPosition.TOP,
            duration=2000,
            parent=self
        )

    def is_signed_decimal(self, s):
        return bool(re.fullmatch(r'[-+]?\d+(\.\d+)?', s))

    @Slot()
    def SendData(self):
        TxDataBuffer = Send510ContralCode(self.LeftSpeed, self.RightSpeed, self.ArmState)
        self.serialHandle.SendFrame(TxDataBuffer)
        self.DateSend_textedit.appendPlainText(BytesToStrOnTime(TxDataBuffer).upper())

    @Slot()
    def AutoSend(self):
        if self.IsAotoSend_sbtn.isChecked():
            self.timer.start(100)
            # print('True')
            pass
        else:
            self.timer.stop()
            # print('False')
            pass
        pass

    @Slot(str)
    def OnSelectBaudRate(self, message):
        value = int(message)
        self.serialHandle.SetBaudRate(value)

    @Slot()
    def OnArmUpbtnIsPressed(self):
        self.ArmState = 1

    @Slot()
    def OnArmbtnNonePressed(self):
        self.ArmState = 0

    @Slot()
    def OnArmDownbtnIsPressed(self):
        self.ArmState = -1
